package betterbluetoothle.tests; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.content.Context; import org.jdeferred.DoneCallback; import org.jdeferred.ProgressCallback; import org.jdeferred.Promise; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import java.util.UUID; import betterbluetoothle.async.AsyncBluetoothGatt; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) public class AsyncBluetoothGattTest { private UUID TEST_UUID1 = UUID.fromString("12345678-0000-1000-8000-00805f9b34fb"); private UUID TEST_UUID2 = UUID.fromString("87654321-0000-1000-8000-00805f9b34fb"); private int testRssi; private BluetoothGattCharacteristic testCh; private BluetoothGattDescriptor testDs; private int testCount; @Before public void setup() { testRssi = 0; testCh = null; testDs = null; testCount = 0; } // Build a mock BluetoothGattService of the specified UUID and instance ID. private BluetoothGattService mockService(UUID uuid, int instanceId) { BluetoothGattService service = mock(BluetoothGattService.class); when(service.getUuid()).thenReturn(uuid); when(service.getInstanceId()).thenReturn(instanceId); return service; } // Build a mock BluetoothGattCharacteristic of the specified UUID, instance ID, and parent service. private BluetoothGattCharacteristic mockCharacteristic(UUID uuid, int instanceId, BluetoothGattService parent) { BluetoothGattCharacteristic ch = mock(BluetoothGattCharacteristic.class); when(ch.getUuid()).thenReturn(uuid); when(ch.getInstanceId()).thenReturn(instanceId); when(ch.getService()).thenReturn(parent); return ch; } // Build a mock BluetoothGattDescriptor of the specified UUID and parent characteristic. private BluetoothGattDescriptor mockDescriptor(UUID uuid, BluetoothGattCharacteristic parent) { BluetoothGattDescriptor descriptor = mock(BluetoothGattDescriptor.class); when(descriptor.getUuid()).thenReturn(uuid); when(descriptor.getCharacteristic()).thenReturn(parent); return descriptor; } // Build an AsyncBluetoothGatt instance that is connected. private AsyncBluetoothGatt connectedAsyncGatt() { BluetoothDevice device = mock(BluetoothDevice.class); Context context = mock(Context.class); BluetoothGatt mockGatt = mock(BluetoothGatt.class); AsyncBluetoothGatt gatt = new AsyncBluetoothGatt(device, context, false); when(device.connectGatt(context, false, gatt)).thenReturn(mockGatt); gatt.connect(); return gatt; } @Test public void test_connect_immediate_failure_rejects_promise() throws Exception { BluetoothDevice device = mock(BluetoothDevice.class); Context context = mock(Context.class); AsyncBluetoothGatt gatt = new AsyncBluetoothGatt(device, context, false); when(device.connectGatt(context, false, gatt)).thenReturn(null); Promise<Void, Integer, Void> connected = gatt.connect(); assertThat(connected.isPending()).isFalse(); assertThat(connected.isRejected()).isTrue(); assertThat(connected.isResolved()).isFalse(); } @Test public void test_connect_is_pending_before_update() throws Exception { BluetoothDevice device = mock(BluetoothDevice.class); Context context = mock(Context.class); BluetoothGatt mockGatt = mock(BluetoothGatt.class); AsyncBluetoothGatt gatt = new AsyncBluetoothGatt(device, context, false); when(device.connectGatt(context, false, gatt)).thenReturn(mockGatt); Promise<Void, Integer, Void> connected = gatt.connect(); Promise<Void, Integer, Void> disconnected = gatt.disconnected(); assertThat(connected.isPending()).isTrue(); assertThat(connected.isRejected()).isFalse(); assertThat(connected.isResolved()).isFalse(); assertThat(disconnected.isPending()).isTrue(); assertThat(disconnected.isRejected()).isFalse(); assertThat(disconnected.isResolved()).isFalse(); } @Test public void test_connect_success_resolves_promise() throws Exception { BluetoothDevice device = mock(BluetoothDevice.class); Context context = mock(Context.class); BluetoothGatt mockGatt = mock(BluetoothGatt.class); AsyncBluetoothGatt gatt = new AsyncBluetoothGatt(device, context, false); when(device.connectGatt(context, false, gatt)).thenReturn(mockGatt); Promise<Void, Integer, Void> connected = gatt.connect(); Promise<Void, Integer, Void> disconnected = gatt.disconnected(); gatt.onConnectionStateChange(mockGatt, BluetoothGatt.GATT_SUCCESS, BluetoothGatt.STATE_CONNECTED); assertThat(connected.isPending()).isFalse(); assertThat(connected.isRejected()).isFalse(); assertThat(connected.isResolved()).isTrue(); assertThat(disconnected.isPending()).isTrue(); assertThat(disconnected.isRejected()).isFalse(); assertThat(disconnected.isResolved()).isFalse(); } @Test public void test_connect_failure_rejects_promise() throws Exception { BluetoothDevice device = mock(BluetoothDevice.class); Context context = mock(Context.class); BluetoothGatt mockGatt = mock(BluetoothGatt.class); AsyncBluetoothGatt gatt = new AsyncBluetoothGatt(device, context, false); when(device.connectGatt(context, false, gatt)).thenReturn(mockGatt); Promise<Void, Integer, Void> connected = gatt.connect(); gatt.onConnectionStateChange(mockGatt, BluetoothGatt.GATT_FAILURE, BluetoothGatt.STATE_CONNECTED); assertThat(connected.isPending()).isFalse(); assertThat(connected.isRejected()).isTrue(); assertThat(connected.isResolved()).isFalse(); } // TODO: Test reconnect. Should reconnect close the previous connect/disconnect promise? @Test public void test_disconnect_resolves_disconnected_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); Promise<Void, Integer, Void> disconnected = gatt.disconnected(); gatt.disconnect(); assertThat(disconnected.isPending()).isFalse(); assertThat(disconnected.isRejected()).isFalse(); assertThat(disconnected.isResolved()).isTrue(); } @Test public void test_disconnect_event_resolves_disconnected_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); Promise<Void, Integer, Void> disconnected = gatt.disconnected(); gatt.onConnectionStateChange(gatt.getGatt(), BluetoothGatt.GATT_SUCCESS, BluetoothGatt.STATE_DISCONNECTED); assertThat(disconnected.isPending()).isFalse(); assertThat(disconnected.isRejected()).isFalse(); assertThat(disconnected.isResolved()).isTrue(); } @Test public void test_close_causes_disconnect() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); Promise<Void, Integer, Void> disconnected = gatt.disconnected(); gatt.close(); assertThat(disconnected.isPending()).isFalse(); assertThat(disconnected.isRejected()).isFalse(); assertThat(disconnected.isResolved()).isTrue(); } @Test public void test_discover_service_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().discoverServices()).thenReturn(false); Promise<Void, Integer, Void> discovered = gatt.discoverServices(); assertThat(discovered.isPending()).isFalse(); assertThat(discovered.isRejected()).isTrue(); assertThat(discovered.isResolved()).isFalse(); } @Test public void test_discover_service_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().discoverServices()).thenReturn(true); Promise<Void, Integer, Void> discovered = gatt.discoverServices(); assertThat(discovered.isPending()).isTrue(); assertThat(discovered.isRejected()).isFalse(); assertThat(discovered.isResolved()).isFalse(); } @Test public void test_discover_service_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().discoverServices()).thenReturn(true); Promise<Void, Integer, Void> discovered = gatt.discoverServices(); gatt.onServicesDiscovered(gatt.getGatt(), BluetoothGatt.GATT_SUCCESS); assertThat(discovered.isPending()).isFalse(); assertThat(discovered.isRejected()).isFalse(); assertThat(discovered.isResolved()).isTrue(); } @Test public void test_discover_service_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().discoverServices()).thenReturn(true); Promise<Void, Integer, Void> discovered = gatt.discoverServices(); gatt.onServicesDiscovered(gatt.getGatt(), BluetoothGatt.GATT_FAILURE); assertThat(discovered.isPending()).isFalse(); assertThat(discovered.isRejected()).isTrue(); assertThat(discovered.isResolved()).isFalse(); } @Test public void test_read_rssi_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().readRemoteRssi()).thenReturn(false); Promise<Integer, Integer, Void> readRssi = gatt.readRemoteRssi(); assertThat(readRssi.isPending()).isFalse(); assertThat(readRssi.isRejected()).isTrue(); assertThat(readRssi.isResolved()).isFalse(); } @Test public void test_read_rssi_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().readRemoteRssi()).thenReturn(true); Promise<Integer, Integer, Void> readRssi = gatt.readRemoteRssi(); assertThat(readRssi.isPending()).isTrue(); assertThat(readRssi.isRejected()).isFalse(); assertThat(readRssi.isResolved()).isFalse(); } @Test public void test_read_rssi_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().readRemoteRssi()).thenReturn(true); Promise<Integer, Integer, Void> readRssi = gatt.readRemoteRssi(); gatt.onReadRemoteRssi(gatt.getGatt(), 100, BluetoothGatt.GATT_SUCCESS); assertThat(readRssi.isPending()).isFalse(); assertThat(readRssi.isRejected()).isFalse(); assertThat(readRssi.isResolved()).isTrue(); readRssi.done(new DoneCallback<Integer>() { @Override public void onDone(Integer result) { testRssi = result; } }); assertThat(testRssi).isEqualTo(100); } @Test public void test_read_rssi_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); when(gatt.getGatt().readRemoteRssi()).thenReturn(true); Promise<Integer, Integer, Void> readRssi = gatt.readRemoteRssi(); gatt.onReadRemoteRssi(gatt.getGatt(), 0, BluetoothGatt.GATT_FAILURE); assertThat(readRssi.isPending()).isFalse(); assertThat(readRssi.isRejected()).isTrue(); assertThat(readRssi.isResolved()).isFalse(); } @Test public void test_read_characteristic_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().readCharacteristic(ch)).thenReturn(false); Promise<BluetoothGattCharacteristic, Integer, Void> readCh = gatt.readCharacteristic(ch); assertThat(readCh.isPending()).isFalse(); assertThat(readCh.isRejected()).isTrue(); assertThat(readCh.isResolved()).isFalse(); } @Test public void test_read_characteristic_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().readCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> readCh = gatt.readCharacteristic(ch); assertThat(readCh.isPending()).isTrue(); assertThat(readCh.isRejected()).isFalse(); assertThat(readCh.isResolved()).isFalse(); } @Test public void test_read_characteristic_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().readCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> readCh = gatt.readCharacteristic(ch); gatt.onCharacteristicRead(gatt.getGatt(), ch, BluetoothGatt.GATT_SUCCESS); assertThat(readCh.isPending()).isFalse(); assertThat(readCh.isRejected()).isFalse(); assertThat(readCh.isResolved()).isTrue(); readCh.done(new DoneCallback<BluetoothGattCharacteristic>() { @Override public void onDone(BluetoothGattCharacteristic result) { testCh = result; } }); assertThat(testCh).isEqualTo(ch); } @Test public void test_read_characteristic_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().readCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> readCh = gatt.readCharacteristic(ch); gatt.onCharacteristicRead(gatt.getGatt(), ch, BluetoothGatt.GATT_FAILURE); assertThat(readCh.isPending()).isFalse(); assertThat(readCh.isRejected()).isTrue(); assertThat(readCh.isResolved()).isFalse(); } @Test public void test_read_multiple_characteristics() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch1 = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattCharacteristic ch2 = mockCharacteristic(TEST_UUID2, 0, service); when(gatt.getGatt().readCharacteristic(ch1)).thenReturn(true); when(gatt.getGatt().readCharacteristic(ch2)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> readCh1 = gatt.readCharacteristic(ch1); Promise<BluetoothGattCharacteristic, Integer, Void> readCh2 = gatt.readCharacteristic(ch2); gatt.onCharacteristicRead(gatt.getGatt(), ch2, BluetoothGatt.GATT_SUCCESS); assertThat(readCh1.isPending()).isTrue(); assertThat(readCh1.isRejected()).isFalse(); assertThat(readCh1.isResolved()).isFalse(); assertThat(readCh2.isPending()).isFalse(); assertThat(readCh2.isRejected()).isFalse(); assertThat(readCh2.isResolved()).isTrue(); readCh2.done(new DoneCallback<BluetoothGattCharacteristic>() { @Override public void onDone(BluetoothGattCharacteristic result) { testCh = result; } }); assertThat(testCh).isEqualTo(ch2); } @Test public void test_write_characteristic_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().writeCharacteristic(ch)).thenReturn(false); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh = gatt.writeCharacteristic(ch); assertThat(writeCh.isPending()).isFalse(); assertThat(writeCh.isRejected()).isTrue(); assertThat(writeCh.isResolved()).isFalse(); } @Test public void test_write_characteristic_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().writeCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh = gatt.writeCharacteristic(ch); assertThat(writeCh.isPending()).isTrue(); assertThat(writeCh.isRejected()).isFalse(); assertThat(writeCh.isResolved()).isFalse(); } @Test public void test_write_characteristic_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().writeCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh = gatt.writeCharacteristic(ch); gatt.onCharacteristicWrite(gatt.getGatt(), ch, BluetoothGatt.GATT_SUCCESS); assertThat(writeCh.isPending()).isFalse(); assertThat(writeCh.isRejected()).isFalse(); assertThat(writeCh.isResolved()).isTrue(); writeCh.done(new DoneCallback<BluetoothGattCharacteristic>() { @Override public void onDone(BluetoothGattCharacteristic result) { testCh = result; } }); assertThat(testCh).isEqualTo(ch); } @Test public void test_write_characteristic_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().writeCharacteristic(ch)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh = gatt.writeCharacteristic(ch); gatt.onCharacteristicWrite(gatt.getGatt(), ch, BluetoothGatt.GATT_FAILURE); assertThat(writeCh.isPending()).isFalse(); assertThat(writeCh.isRejected()).isTrue(); assertThat(writeCh.isResolved()).isFalse(); } @Test public void test_write_multiple_characteristics() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch1 = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattCharacteristic ch2 = mockCharacteristic(TEST_UUID2, 0, service); when(gatt.getGatt().writeCharacteristic(ch1)).thenReturn(true); when(gatt.getGatt().writeCharacteristic(ch2)).thenReturn(true); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh1 = gatt.writeCharacteristic(ch1); Promise<BluetoothGattCharacteristic, Integer, Void> writeCh2 = gatt.writeCharacteristic(ch2); gatt.onCharacteristicWrite(gatt.getGatt(), ch2, BluetoothGatt.GATT_SUCCESS); assertThat(writeCh1.isPending()).isTrue(); assertThat(writeCh1.isRejected()).isFalse(); assertThat(writeCh1.isResolved()).isFalse(); assertThat(writeCh2.isPending()).isFalse(); assertThat(writeCh2.isRejected()).isFalse(); assertThat(writeCh2.isResolved()).isTrue(); writeCh2.done(new DoneCallback<BluetoothGattCharacteristic>() { @Override public void onDone(BluetoothGattCharacteristic result) { testCh = result; } }); assertThat(testCh).isEqualTo(ch2); } @Test public void test_read_descriptor_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().readDescriptor(ds)).thenReturn(false); Promise<BluetoothGattDescriptor, Integer, Void> readDs = gatt.readDescriptor(ds); assertThat(readDs.isPending()).isFalse(); assertThat(readDs.isRejected()).isTrue(); assertThat(readDs.isResolved()).isFalse(); } @Test public void test_read_descriptor_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().readDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> readDs = gatt.readDescriptor(ds); assertThat(readDs.isPending()).isTrue(); assertThat(readDs.isRejected()).isFalse(); assertThat(readDs.isResolved()).isFalse(); } @Test public void test_read_descriptor_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().readDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> readDs = gatt.readDescriptor(ds); gatt.onDescriptorRead(gatt.getGatt(), ds, BluetoothGatt.GATT_SUCCESS); assertThat(readDs.isPending()).isFalse(); assertThat(readDs.isRejected()).isFalse(); assertThat(readDs.isResolved()).isTrue(); readDs.done(new DoneCallback<BluetoothGattDescriptor>() { @Override public void onDone(BluetoothGattDescriptor result) { testDs = result; } }); assertThat(testDs).isEqualTo(ds); } @Test public void test_read_descriptor_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().readDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> readDs = gatt.readDescriptor(ds); gatt.onDescriptorRead(gatt.getGatt(), ds, BluetoothGatt.GATT_FAILURE); assertThat(readDs.isPending()).isFalse(); assertThat(readDs.isRejected()).isTrue(); assertThat(readDs.isResolved()).isFalse(); } @Test public void test_read_multiple_descriptors() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds1 = mockDescriptor(TEST_UUID1, ch); BluetoothGattDescriptor ds2 = mockDescriptor(TEST_UUID2, ch); when(gatt.getGatt().readDescriptor(ds1)).thenReturn(true); when(gatt.getGatt().readDescriptor(ds2)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> readDs1 = gatt.readDescriptor(ds1); Promise<BluetoothGattDescriptor, Integer, Void> readDs2 = gatt.readDescriptor(ds2); gatt.onDescriptorRead(gatt.getGatt(), ds2, BluetoothGatt.GATT_SUCCESS); assertThat(readDs1.isPending()).isTrue(); assertThat(readDs1.isRejected()).isFalse(); assertThat(readDs1.isResolved()).isFalse(); assertThat(readDs2.isPending()).isFalse(); assertThat(readDs2.isRejected()).isFalse(); assertThat(readDs2.isResolved()).isTrue(); readDs2.done(new DoneCallback<BluetoothGattDescriptor>() { @Override public void onDone(BluetoothGattDescriptor result) { testDs = result; } }); assertThat(testDs).isEqualTo(ds2); } @Test public void test_write_descriptor_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().writeDescriptor(ds)).thenReturn(false); Promise<BluetoothGattDescriptor, Integer, Void> writeDs = gatt.writeDescriptor(ds); assertThat(writeDs.isPending()).isFalse(); assertThat(writeDs.isRejected()).isTrue(); assertThat(writeDs.isResolved()).isFalse(); } @Test public void test_write_descriptor_is_pending_before_update() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().writeDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> writeDs = gatt.writeDescriptor(ds); assertThat(writeDs.isPending()).isTrue(); assertThat(writeDs.isRejected()).isFalse(); assertThat(writeDs.isResolved()).isFalse(); } @Test public void test_write_descriptor_success_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().writeDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> writeDs = gatt.writeDescriptor(ds); gatt.onDescriptorWrite(gatt.getGatt(), ds, BluetoothGatt.GATT_SUCCESS); assertThat(writeDs.isPending()).isFalse(); assertThat(writeDs.isRejected()).isFalse(); assertThat(writeDs.isResolved()).isTrue(); writeDs.done(new DoneCallback<BluetoothGattDescriptor>() { @Override public void onDone(BluetoothGattDescriptor result) { testDs = result; } }); assertThat(testDs).isEqualTo(ds); } @Test public void test_write_descriptor_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds = mockDescriptor(TEST_UUID1, ch); when(gatt.getGatt().writeDescriptor(ds)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> writeDs = gatt.writeDescriptor(ds); gatt.onDescriptorWrite(gatt.getGatt(), ds, BluetoothGatt.GATT_FAILURE); assertThat(writeDs.isPending()).isFalse(); assertThat(writeDs.isRejected()).isTrue(); assertThat(writeDs.isResolved()).isFalse(); } @Test public void test_write_multiple_descriptors() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattDescriptor ds1 = mockDescriptor(TEST_UUID1, ch); BluetoothGattDescriptor ds2 = mockDescriptor(TEST_UUID2, ch); when(gatt.getGatt().writeDescriptor(ds1)).thenReturn(true); when(gatt.getGatt().writeDescriptor(ds2)).thenReturn(true); Promise<BluetoothGattDescriptor, Integer, Void> writeDs1 = gatt.writeDescriptor(ds1); Promise<BluetoothGattDescriptor, Integer, Void> writeDs2 = gatt.writeDescriptor(ds2); gatt.onDescriptorWrite(gatt.getGatt(), ds2, BluetoothGatt.GATT_SUCCESS); assertThat(writeDs1.isPending()).isTrue(); assertThat(writeDs1.isRejected()).isFalse(); assertThat(writeDs1.isResolved()).isFalse(); assertThat(writeDs2.isPending()).isFalse(); assertThat(writeDs2.isRejected()).isFalse(); assertThat(writeDs2.isResolved()).isTrue(); writeDs2.done(new DoneCallback<BluetoothGattDescriptor>() { @Override public void onDone(BluetoothGattDescriptor result) { testDs = result; } }); assertThat(testDs).isEqualTo(ds2); } @Test public void test_set_notification_immediate_failure_rejects_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().setCharacteristicNotification(ch, true)).thenReturn(false); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh = gatt.setCharacteristicNotification(ch, true); assertThat(notifyCh.isPending()).isFalse(); assertThat(notifyCh.isRejected()).isTrue(); assertThat(notifyCh.isResolved()).isFalse(); } @Test public void test_set_notification_is_pending_on_success() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().setCharacteristicNotification(ch, true)).thenReturn(true); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh = gatt.setCharacteristicNotification(ch, true); assertThat(notifyCh.isPending()).isTrue(); assertThat(notifyCh.isRejected()).isFalse(); assertThat(notifyCh.isResolved()).isFalse(); } @Test public void test_set_notification_update_calls_progress() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().setCharacteristicNotification(ch, true)).thenReturn(true); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh = gatt.setCharacteristicNotification(ch, true); notifyCh.progress(new ProgressCallback<BluetoothGattCharacteristic>() { @Override public void onProgress(BluetoothGattCharacteristic progress) { testCh = progress; testCount += 1; } }); gatt.onCharacteristicChanged(gatt.getGatt(), ch); gatt.onCharacteristicChanged(gatt.getGatt(), ch); assertThat(testCh).isEqualTo(ch); assertThat(testCount).isEqualTo(2); } @Test public void test_set_notification_disable_resolves_promise() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch = mockCharacteristic(TEST_UUID1, 0, service); when(gatt.getGatt().setCharacteristicNotification(ch, true)).thenReturn(true); when(gatt.getGatt().setCharacteristicNotification(ch, false)).thenReturn(true); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh = gatt.setCharacteristicNotification(ch, true); Promise<Void, Void, BluetoothGattCharacteristic> disableCh = gatt.setCharacteristicNotification(ch, false); assertThat(notifyCh.isPending()).isFalse(); assertThat(notifyCh.isRejected()).isFalse(); assertThat(notifyCh.isResolved()).isTrue(); assertThat(disableCh.isPending()).isFalse(); assertThat(disableCh.isRejected()).isFalse(); assertThat(disableCh.isResolved()).isTrue(); } @Test public void test_set_notification_multiple_characteristics() throws Exception { AsyncBluetoothGatt gatt = connectedAsyncGatt(); BluetoothGattService service = mockService(TEST_UUID1, 0); BluetoothGattCharacteristic ch1 = mockCharacteristic(TEST_UUID1, 0, service); BluetoothGattCharacteristic ch2 = mockCharacteristic(TEST_UUID2, 0, service); when(gatt.getGatt().setCharacteristicNotification(ch1, true)).thenReturn(true); when(gatt.getGatt().setCharacteristicNotification(ch2, true)).thenReturn(true); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh1 = gatt.setCharacteristicNotification(ch1, true); Promise<Void, Void, BluetoothGattCharacteristic> notifyCh2 = gatt.setCharacteristicNotification(ch2, true); notifyCh1.progress(new ProgressCallback<BluetoothGattCharacteristic>() { @Override public void onProgress(BluetoothGattCharacteristic progress) { testCount = -1; } }); notifyCh2.progress(new ProgressCallback<BluetoothGattCharacteristic>() { @Override public void onProgress(BluetoothGattCharacteristic progress) { testCount = 1; } }); gatt.onCharacteristicChanged(gatt.getGatt(), ch2); assertThat(testCount).isEqualTo(1); } }